package extend.db.base;

import extend.db.Builder;
import extend.db.DbManager;
import extend.db.entity.Entity;
import extend.db.entity.annotation.EntityMetadata;

import java.lang.reflect.Method;
import java.util.*;

/**
 * 实体基类
 *<B>说明：</B>
 *<pre>
 *  提供查询,更新操作
 *</pre>
 *<B>示例：</B>
 *<pre>
 *  略
 *</pre>
 *<B>日志：</B>
 *<pre>
 *  略
 *</pre>
 *<B>注意事项：</B>
 *<pre>
 *  略
 *</pre>
 */
abstract public class BaseDao
{

    public Class entity = hehe.User.class;

    public String tableName;

    public String dbKey;

    protected Query query = new Query();

    public BaseDao(){};

    public BaseDao(String tableName)
    {
        this.query.setTable(tableName);
        this.tableName = tableName;
    }

    public BaseDao(String tableName,String dbKey)
    {
        this.tableName = tableName;
        this.dbKey = dbKey;
    }

    public BaseDao table(String tableName)
    {
        this.query.setTable(tableName);

        return this;
    }

    /**
     * 设置添加数据
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao data(Map<String,Object> data)
    {
        this.query.setData(data);

        return this;
    }

    /**
     * 设置表别名
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao alias(String alias)
    {
        this.query.setAlias(alias);

        return this;
    }

    /**
     * 设置表别名
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao lock(boolean lock)
    {
        this.query.setLock(lock);

        return this;
    }

    /**
     * 设置查询字段
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao field(Object fields)
    {
        this.query.setField(fields);

        return this;
    }

    /**
     * 设置排序规则
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao orderBy(String name, String orderBy)
    {
        SqlMap orderByMap = SqlMap.make();
        orderByMap.put(name,orderBy);
        this.orderBy(orderByMap);

        return this;
    }

    /**
     * 设置排序规则
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao orderBy(Map<String,Object> orderBy)
    {
        this.query.setOrderBy(orderBy);

        return this;
    }

    /**
     * 设置分组规则
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao groupBy(String... groupBy)
    {
        this.query.setGroupBy(groupBy);

        return this;
    }

    public BaseDao union(Query query)
    {
        this.query.addUnion(query);

        return this;
    }

    public BaseDao union(Query query,String unionMode)
    {
        this.query.addUnion(query,unionMode);

        return this;
    }

    protected BaseDao setEntity(Class entity)
    {
        this.query.setEntity(entity);

        return this;
    }


    /**
     * 设置更新行数
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param limit 行数
     * @return this
     */
    public BaseDao limit(int limit)
    {
        this.query.setLimit(limit);

        return this;
    }

    /**
     * 设置更新起始行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param offset 起始位置 0 为第一个行
     * @return this
     */
    public BaseDao offset(int offset)
    {
        this.query.setOffset(offset);

        return this;
    }

    /**
     * 设置分组条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao having(Map<String,Object> condition)
    {
        //  判断是否字符串
        SqlMap having = this.getRawHaving();
        having.add(condition);
        this.query.setHaving(having);

        return this;
    }

    /**
     * 设置分组OR条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao orHaving(Map<String,Object> condition)
    {
        SqlMap newWhere = SqlMap.make();
        SqlMap where = this.getRawHaving();
        newWhere.put(Builder.XOR_EXP,Builder.OR_EXP);
        newWhere.add(where);
        newWhere.add(condition);
        this.query.setHaving(newWhere);

        return this;
    }

    /**
     * 设置分组OR条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao andHaving(Map<String,Object> condition)
    {
        SqlMap newWhere = new SqlMap();
        SqlMap where = this.getRawHaving();
        newWhere.put(Builder.XOR_EXP,Builder.AND_EXP);
        newWhere.add(where);
        newWhere.add(condition);
        this.query.setHaving(newWhere);

        return this;
    }

    public BaseDao where(String field, Object condition)
    {
        return this.where(field,condition,null);
    }

    public BaseDao where(String field, Object condition, String operator)
    {
        SqlMap where = this.getRawWhere();

        if (operator != null) {
            where.exp(field,operator,condition);
            this.query.setWhere(where);
            return this;
        }

        if (condition.getClass().isArray()) {
            operator = Builder.IN_EXP;
        } else {
            operator = Builder.EQ_EXP;
        }

        where.exp(field,operator,condition);
        this.query.setWhere(where);

        return this;
    }


    /**
     * 设置条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao where(Map<String,Object> condition)
    {
        SqlMap where = this.getRawWhere();
        where.add(condition);
        this.query.setWhere(where);

        return this;
    }

    /**
     * 设置or条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao orWhere(Map<String,Object> condition)
    {
        SqlMap newWhere = new SqlMap();
        SqlMap where = this.getRawWhere();
        newWhere.put(Builder.XOR_EXP,Builder.OR_EXP);
        newWhere.add(where);
        newWhere.add(condition);
        this.query.setWhere(newWhere);

        return this;
    }

    /**
     * 设置AND条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    public BaseDao andWhere(Map<String,Object> condition)
    {
        SqlMap newWhere = new SqlMap();
        SqlMap where = this.getRawWhere();
        newWhere.put(Builder.XOR_EXP,Builder.AND_EXP);
        newWhere.add(where);
        newWhere.add(condition);
        this.query.setWhere(newWhere);

        return this;
    }

    public BaseDao toQuery()
    {
        this.query.setToQuery(true);

        return this;
    }

    /**
     * 获取设置过的Having条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    protected SqlMap getRawHaving()
    {
        SqlMap where;
        if (this.query.getHaving() == null) {
            where = new SqlMap();
        } else {
            where = (SqlMap)this.query.getHaving();
        }

        return where;
    }

    /**
     * 获取设置过的where条件
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return this
     */
    protected SqlMap getRawWhere()
    {
        SqlMap where;
        if (this.query.getWhere() == null) {
            where = new SqlMap();
        } else {
            where = (SqlMap)this.query.getWhere();
        }

        return where;
    }


    /**
     * 添加一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    public <T> T addOne()
    {
        return (T)this.addRow();
    }

    /**
     * 添加一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param entity 数据
     * @return int
     */
    public <T> T addOne(Object entity)
    {
        EntityMetadata entityMetadata = Entity.getEntity(entity);
        String tableName = entityMetadata.getTableName();
        if (tableName != null && !tableName.equals("")) {
            this.table(tableName);
        }

        Map<String,Object> data = Entity.toAdd(entity);

        if (data != null) {
            this.data(data);
        }

        return (T)this.addRow();
    }

    /**
     * 批量添加
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public <T> T addAll()
    {
        return (T)this.addRows();
    }

    /**
     * 批量添加
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public <T> T addAll(List<Object> entitys)
    {

        Object firstEntity = entitys.get(0);

        EntityMetadata entityMetadata = Entity.getEntity(firstEntity);
        String tableName = entityMetadata.getTableName();
        if (tableName != null && !tableName.equals("")) {
            this.table(tableName);
        }

        for (Object entity:entitys) {
            Map<String,Object> data = Entity.toAdd(entity);
            if (data != null) {
                this.data(data);
            }
        }

        return (T)this.addRows();
    }

    /**
     * 更新一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    public <T> T updateOne()
    {
        return (T)this.limit(1).updateRows();
    }

    /**
     * 更新一条数据行
     *<B>说明：</B>
     *<pre>
     *  以主键未更新条件
     *</pre>
     * @param entity 实体
     * @return int
     */
    public <T> T updateOne(Object entity)
    {
        EntityMetadata entityMetadata = Entity.getEntity(entity);
        String tableName = entityMetadata.getTableName();
        if (tableName != null && !tableName.equals("")) {
            this.table(tableName);
        }


        Map<String,Map<String,Object>> condition = Entity.toUpdate(entity);
        Map<String,Object> where = condition.get(Entity.WHERE_NAME);
        if (where == null && where.size() == 0) {
            return null;
        }

        this.where(where);

        Map<String,Object> data = condition.get(Entity.DATA_NAME);
        if ( data != null) {
            this.data(data);
        }

        this.limit(1);

        return (T)this.updateRows();
    }

    /**
     * 根据条件更新数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    public <T> T updateAll()
    {
        return (T)this.updateRows();
    }

    /**
     * 根据条件更新数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param entity 更新实体
     * @return int
     */
    public <T> T updateAll(Object entity)
    {

        EntityMetadata entityMetadata = Entity.getEntity(entity);
        String tableName = entityMetadata.getTableName();
        if (tableName != null && !tableName.equals("")) {
            this.table(tableName);
        }

        Map<String,Map<String,Object>> condition = Entity.toUpdate(entity);
        Map<String,Object> where = condition.get(Entity.WHERE_NAME);
        if (where == null && where.size() == 0) {
            return null;
        }

        this.where(where);

        Map<String,Object> data = condition.get(Entity.DATA_NAME);
        if ( data != null) {
            this.data(data);
        }

        return (T)this.updateRows();
    }

    /**
     * 删除一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    public <T> T deleteOne()
    {
        return (T)this.limit(1).deleteRows();
    }

    /**
     * 删除一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param entity 删除条件
     * @return int
     */
    public <T> T deleteOne(Object entity)
    {
        Map<String,Object> where = Entity.toDelete(entity);

        if (where == null && where.size() == 0) {
            return null;
        }

        this.where(where);
        this.limit(1);

        return (T)this.deleteRows();
    }

    /**
     * 根据条件删除数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    public <T> T deleteAll()
    {
        return (T)this.deleteRows();
    }

    /**
     * 根据条件删除数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param entity 删除条件
     * @return int
     */
    public <T> T deleteAll(Object entity)
    {
        Map<String,Object> where = Entity.toDelete(entity);

        if (where == null && where.size() == 0) {
            return null;
        }

        this.where(where);

        return (T)this.deleteRows();
    }



    /**
     * 根据条件读取一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return Map
     */
    public <T> T one()
    {
        return (T)this.limit(1).queryRow();
    }

    /**
     * 根据条件读取一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param where 查询条件
     * @return Map
     */
    public <T> T one(Map<String,Object> where)
    {
        if (where != null) {
            this.where(where);
        }

        this.limit(1);

        return (T)this.queryRow();
    }

    public <T> T one(Class entity)
    {
        this.setEntity(entity);

        this.limit(1);

        return (T)this.queryRow();
    }

    /**
     * 根据条件读取多条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return List
     */
    public <T> T all()
    {
        return (T)this.queryRows();
    }

    /**
     * 根据条件读取多条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @param where 查询条件
     * @return List
     */
    public <T> T  all(Map<String,Object> where)
    {
        if (where != null) {
            this.where(where);
        }

        return (T)this.queryRows();
    }

    /**
     * 根据条件读取多条数据行
     *<B>说明：</B>
     *<pre>
     *  数据行转换实体对象
     *</pre>
     * @param entity 查询条件
     * @return List
     */
    public <T> T  all(Class entity)
    {
        this.setEntity(entity);

        return (T)this.queryRows();
    }



    /**
     * 添加数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    protected Object addRow()
    {
        Query query = this.getQuery(null);
        query.setBuildMethod(Query.BUILD_INSERT);

        if (query.getToQuery()) {
            return query;
        }

        this.addInternal(query);

        return  query.getResult();
    }

    /**
     * 添加多行数据
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    protected Object addRows()
    {
        Query query = this.getQuery(null);
        query.setBuildMethod(Query.BUILD_INSERT_ALL);

        if (query.getToQuery()) {
            return query;
        }

        this.addInternal(query);

        return query.getResult();
    }

    /**
     * 更新数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    protected Object updateRows()
    {
        Query query = this.getQuery(null);
        query.setBuildMethod(Query.BUILD_UPDATE);
        if (query.getToQuery()) {
            return query;
        }

        this.updateInternal(query);

        return query.getResult();
    }

    /**
     * 删除数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return int
     */
    protected Object deleteRows()
    {
        Query query = this.getQuery(null);
        query.setBuildMethod(Query.BUILD_DELETE);

        if (query.getToQuery()) {
            return query;
        }

        this.deleteInternal(query);

        return query.getResult();
    }

    /**
     * 查詢一条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return Map
     */
    protected Object queryRow()
    {
        Query query = this.getQuery(null);
        query.setBuildMethod(Query.BUILD_SELECT);

        if (query.getToQuery()) {
            return query;
        }

        this.queryInternal(query);
        Object result = query.getResult();
        if (result == null) {
            return null;
        }

        List resultList = (ArrayList)result;
        if (resultList.size() == 0) {
            return null;
        }

        return  resultList.get(0);
    }

    /**
     *　查詢多条数据行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return List
     */
    protected Object queryRows()
    {
        Query query = this.getQuery(null);
        query.setBuildMethod(Query.BUILD_SELECT);

        if (query.getToQuery()) {
            return query;
        }

        this.queryInternal(query);
        Object result = this.toQueryResult(query);
        if (result == null) {
            return null;
        }

        List resultList = (ArrayList)result;
        if (resultList.size() == 0) {
            return null;
        }

        return resultList;
    }

    /**
     * 获取最后一条sql
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     * @return
     */
    public static String getLastSql()
    {
        return DbManager.get().getLastSql();
    }

    // 增.更新,查询接口,
    abstract public Query addInternal(Query query);
    abstract public Query updateInternal(Query query);
    abstract public Query deleteInternal(Query query);
    abstract public Query queryInternal(Query query);

    /**
     * 获取sqlQuery
     *<B>说明：</B>
     *<pre>
     * 1、内部使用
     *</pre>
     * @param options
     * @return Query
     */
    protected Query getQuery(Map<String,Object> options)
    {
        if (options != null) {
            this.query.setAttrs(options);
        }

        // 默认表名处理
        if (this.query.getTable().equals("")) {
            String tableName  = this.invokeTableMethod("tableName");
            if (tableName != null) {
                this.query.setTable(tableName);
            }
        }

        // 默认数据库连接
        if (this.query.getDbkey().equals("")) {
            String dbKey  = this.invokeTableMethod("dbKey");
            if (dbKey != null) {
                this.query.setDbkey(dbKey);
            }
        }

        Query query = this.query;
        this.query = new Query();

        return query;
    }

    /**
     * 执行更新sql命令
     *<B>说明：</B>
     *<pre>
     * 1、内部使用
     *</pre>
     * @param query
     * @return int
     */
    protected int executeCommand(Query query)
    {
        Command command = query.buildParamsCommand();

        try {
            DbManager.get().addSql(command.getSql());
            return query.getDb().execute(command);
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 执行查询sql命令
     *<B>说明：</B>
     *<pre>
     * 1、内部使用
     *</pre>
     * @param query
     * @return List
     */
    protected List<Map<String,Object>> queryCommand(Query query)
    {
        Command command = query.buildParamsCommand();
        try {
            DbManager.get().addSql(command.getSql());
            return query.getDb().query(command);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 执行
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public  <T> T invokeTableMethod(String methodName)
    {
        try {
            // 添加缓存
            Method method = this.getClass().getMethod(methodName);
            return (T)method.invoke(null);
        } catch (Exception ex) {

        }

        return null;
    }

    /**
     * map转成实体对象
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    private Object toQueryResult(Query query)
    {
        try {
            List<Map<String,Object>> rows = (List<Map<String,Object>>)query.getResult();
            if (rows == null) {
                return null;
            }

            if (query.getEntity() == null) {
                return rows;
            }

            List entitys = new ArrayList();
            for (Map<String,Object> row:rows) {
                Object entity = query.getEntity().newInstance();
                Entity.setAttrs(entity,row);
                entitys.add(entity);
            }

            return entitys;
        } catch (Exception ex) {
            return null;
        }
    }

}
